package com.yungu.swift.lbs.trace.baidu.core;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.yungu.swift.constants.MagicConstant;
import com.yungu.swift.lbs.trace.baidu.LBSTraceClient;
import com.yungu.swift.lbs.trace.baidu.model.*;
import com.yungu.swift.lbs.trace.baidu.track.*;
import com.yungu.swift.lbs.trace.baidu.util.BaiduCommonUtils;
import com.yungu.swift.lbs.trace.baidu.util.HttpUtils;
import com.yungu.swift.lbs.trace.baidu.util.TrackUtils;
import com.yungu.swift.utils.DateUtils;
import com.yungu.swift.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;


/**
 * Track处理器
 *
 * @author baidu
 */
@Slf4j
public class TrackHandler {

    /**
     * 添加单个轨迹点（异步）
     * 可用于15秒一次传点时调用
     *
     * @param request
     */
    public static void addPoint(AddPointRequest request) {
        StringBuilder parameters = new StringBuilder();
        packRequest(request, parameters);
        AsyncRequestClient.getInstance().submitTask(request.getRequestID(), UrlDomain.ACTION_ADD_POINT,
                parameters.toString(), HttpClient.METHOD_POST);
    }


    /**
     * 批量添加轨迹点
     *
     * @param request
     */
    public static void addPoints(AddPointsRequest request) {
        StringBuilder parameters = new StringBuilder();
        packRequest(request, parameters);
        AsyncRequestClient.getInstance().submitTask(request.getRequestID(), UrlDomain.ACTION_ADD_POINTS,
                parameters.toString(), HttpClient.METHOD_POST);
    }

    /**
     * 添加单个轨迹点（同步）
     * 可用于15秒一次传点时调用
     *
     * @param request
     */
    public static boolean addPointSync(AddPointRequest request) {
        return addPointSyncCommon(request, UrlDomain.ACTION_ADD_POINT);
    }


    /**
     * 批量添加轨迹点
     *
     * @param request
     */
    public static boolean addPointsSync(AddPointsRequest request) {
        return addPointSyncCommon(request, UrlDomain.ACTION_ADD_POINTS);
    }


    /**
     * 添加轨迹点（同步）
     * 可用于同步阻塞调用
     *
     * @param request
     */
    public static boolean addPointSyncCommon(BaseRequest request, String action) {
        StringBuilder parameters = new StringBuilder();
        packRequest(request, parameters);
        // 发送请求
        String result = HttpClient.sendRequest(action, parameters.toString(), HttpClient.METHOD_POST);
        UploadResponse response = new UploadResponse(request.getRequestID(), StatusCodes.SUCCESS, StatusCodes.MSG_SUCCESS);
        parseCommonResponse(response, result);
        if (response.getStatus() == StatusCodes.SUCCESS) {
            System.out.println("上传成功，" + request.toString());
            return true;
        }
        System.out.println("上传失败，" + response.getMessage());
        return false;
    }

    /**
     * 获取某entity里程
     *
     * @param request
     */
    public static DistanceResponse getDistance(GetDistanceRequest request) {
        StringBuilder parameters = new StringBuilder();
        packRequest(request, parameters);
        // 发送请求
        String result = HttpClient.sendRequest(UrlDomain.ACTION_TRACK_GETDISTANCE, parameters.toString(), HttpClient.METHOD_GET);
        DistanceResponse response = new DistanceResponse(request.getRequestID(), StatusCodes.SUCCESS, StatusCodes.MSG_SUCCESS);
        parseDistanceResponse(response, result);
        if (response.getStatus() == StatusCodes.SUCCESS) {
            return response;
        }
        return null;
    }

    /**
     * 获取某轨迹点
     *
     * @param request
     */
    public static TrackResponse getTrack(GetTrackRequest request) {
        StringBuilder parameters = new StringBuilder();
        packRequest(request, parameters);
        // 发送请求
        String result = HttpClient.sendRequest(UrlDomain.ACTION_TRACK_GETTRACK, parameters.toString(), HttpClient.METHOD_GET);
        TrackResponse response = new TrackResponse(request.getRequestID(), StatusCodes.SUCCESS, StatusCodes.MSG_SUCCESS);
        parseTrackResponse(response, result);
        if (response.getStatus() == StatusCodes.SUCCESS) {
            return response;
        }
        return null;
    }

    /**
     * 获取某entity里程
     *
     * @param request
     */
    public static boolean deleteEntity(DeleteEntityRequest request) {
        StringBuilder parameters = new StringBuilder();
        packRequest(request, parameters);
        // 发送请求
        String result = HttpClient.sendRequest(UrlDomain.ACTION_DELETE_ENTITY, parameters.toString(), HttpClient.METHOD_POST);
        DistanceResponse response = new DistanceResponse(request.getRequestID(), StatusCodes.SUCCESS, StatusCodes.MSG_SUCCESS);
        parseCommonResponse(response, result);
        if (response.getStatus() == StatusCodes.SUCCESS) {
            return true;
        }
        return false;
    }

    /**
     * 获取entity的List
     *
     * @param request
     */
    public static ListEntityResponse listEntity(ListEntityRequest request) {
        StringBuilder parameters = new StringBuilder();
        packRequest(request, parameters);
        // 发送请求
        String result = HttpClient.sendRequest(UrlDomain.ACTION_LIST_ENTITY, parameters.toString(), HttpClient.METHOD_GET);
        ListEntityResponse response = new ListEntityResponse(request.getRequestID(), StatusCodes.SUCCESS, StatusCodes.MSG_SUCCESS);
        parseListEntityResponse(response, result);
        if (response.getStatus() == StatusCodes.SUCCESS) {
            return response;
        }
        return null;
    }

    /**
     * 组装请求
     *
     * @return
     */
    public static void packRequest(BaseRequest request, StringBuilder parameters) {
        if (null == request) {
            throw new IllegalTrackArgumentException("request can not be null.");
        }

        packCommonRequest(request, parameters);

        if (request instanceof AddPointRequest) {
            AddPointRequest addPointRequest = (AddPointRequest) request;
            parameters.append("&entity_name=").append(HttpUtils.urlEncode(addPointRequest.getEntityName()));
            TrackPoint trackPoint = addPointRequest.getTrackPoint();
            if (null == trackPoint) {
                throw new IllegalTrackArgumentException("trackPoint can not be null.");
            }
            TrackUtils.packPoint(trackPoint, parameters);
        } else if (request instanceof AddPointsRequest) {
            AddPointsRequest addPointsRequest = (AddPointsRequest) request;
            TrackUtils.packPoints(addPointsRequest.getTrackPoints(), parameters);
        } else if (request instanceof GetTrackRequest) {
            GetTrackRequest getTrackRequest = (GetTrackRequest) request;
            TrackUtils.packTrack(getTrackRequest, parameters);
        } else if (request instanceof GetDistanceRequest) {
            GetDistanceRequest getDistanceRequest = (GetDistanceRequest) request;
            TrackUtils.packDistance(getDistanceRequest, parameters);
        } else if (request instanceof DeleteEntityRequest) {
            DeleteEntityRequest deleteEntityRequest = (DeleteEntityRequest) request;
            parameters.append("&entity_name=").append(HttpUtils.urlEncode(deleteEntityRequest.getEntityName()));
        } else if (request instanceof ListEntityRequest) {
            ListEntityRequest listEntityRequest = (ListEntityRequest) request;
            TrackUtils.packListEntity(listEntityRequest, parameters);
        }
    }

    /**
     * 组装公共请求
     *
     * @param request
     * @param parameters
     */
    private static void packCommonRequest(BaseRequest request, StringBuilder parameters) {
        if (BaiduCommonUtils.isNullOrEmpty(request.getAk())) {
            throw new IllegalTrackArgumentException("ak can not be null or empty string.");
        }

        if (request.getServiceId() <= 0) {
            throw new IllegalTrackArgumentException("serviceId is lower than 0.");
        }
        parameters.append("ak=").append(request.getAk());
        parameters.append("&service_id=").append(request.getServiceId());
    }

    /**
     * 解析响应
     *
     * @param requestId 响应对应的请求ID
     * @param action    响应对应的请求action
     * @param result    响应结果
     */
    public static void parseResponse(long requestId, String action, String result) {
        List<OnUploadListener> listeners = LBSTraceClient.getInstance().uploadListeners;
        UploadResponse response = new UploadResponse(requestId, StatusCodes.SUCCESS, StatusCodes.MSG_SUCCESS);
        parseCommonResponse(response, result);
        for (OnUploadListener listener : listeners) {
            if (response.getStatus() == StatusCodes.SUCCESS) {
                listener.onSuccess(requestId);
            } else {
                listener.onFailed(response);
            }
        }
    }

    /**
     * 解析通用响应
     *
     * @param response
     * @param result
     */
    private static void parseCommonResponse(BaseResponse response, String result) {
        try {
            JsonNode jsonNode = JsonUtils.readNode(result);
            response.setStatus(jsonNode.get("status").asInt());
            response.setMessage(jsonNode.get("message").asText());
        } catch (Exception e) {
            response.setStatus(StatusCodes.PARSE_FAILED);
            response.setMessage(StatusCodes.MSG_PARSE_FAILED);
        }
    }

    /**
     * 解析获取距离请求
     *
     * @param response
     * @param result
     */
    private static void parseDistanceResponse(DistanceResponse response, String result) {
        parseCommonResponse(response, result);
        if (response.getStatus() == StatusCodes.SUCCESS) {
            try {
                JsonNode jsonNode = JsonUtils.readNode(result);
                if (jsonNode.has(MagicConstant.PARAMS_DISTANCE)) {
                    response.setDistance(jsonNode.get("distance").asDouble());
                }
            } catch (IOException e) {
                log.error("parseDistanceResponse JsonUtils readNode error.result:{}", result);
            }
        }
    }

    /**
     * 解析获取距离请求
     *
     * @param response
     * @param result
     */
    private static void parseTrackResponse(TrackResponse response, String result) {
        parseCommonResponse(response, result);
        if (response.getStatus() == StatusCodes.SUCCESS) {
            try {
                JsonNode jsonNode = JsonUtils.readNode(result);
                if (jsonNode.has(MagicConstant.PARAMS_DISTANCE)) {
                    response.setDistance(jsonNode.get("distance").asDouble());
                }
                if (jsonNode.has(MagicConstant.PARAMS_TOTAL)) {
                    response.setTotal(jsonNode.get("total").asInt());
                }
                if (jsonNode.has(MagicConstant.PARAMS_SIZE)) {
                    response.setSize(jsonNode.get("size").asInt());
                }
                if (jsonNode.has(MagicConstant.PARAMS_TOLL_DISTANCE)) {
                    response.setTollDistance(jsonNode.get("toll_distance").asDouble());
                }
                if (jsonNode.has(MagicConstant.PARAMS_START_POINT)) {
                    Point startPoint = JsonUtils.readValue(jsonNode.get("start_point").asText(), Point.class);
                    response.setStartPoint(startPoint);
                }
                if (jsonNode.has(MagicConstant.PARAMS_END_POINT)) {
                    Point endPoint = JsonUtils.readValue(jsonNode.get("end_point").asText(), Point.class);
                    response.setStartPoint(endPoint);
                }
                if (jsonNode.has(MagicConstant.PARAMS_POINTS)) {
                    List<TrackPoint> trackPoints = JsonUtils.readListValue(jsonNode.get("points").asText(),
                            TrackPoint.class);
                    response.setPoints(trackPoints);
                }


            } catch (IOException e) {
                log.error("parseTrackResponse JsonUtils readNode error.result:{}", result);
            }
        }
    }

    /**
     * 解析获取距离请求
     *
     * @param response
     * @param result
     */
    private static void parseListEntityResponse(ListEntityResponse response, String result) {
        parseCommonResponse(response, result);
        if (response.getStatus() == StatusCodes.SUCCESS) {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                JsonNode jsonNode = JsonUtils.readNode(result);
                response.setTotal(jsonNode.get("total").asInt());
                response.setSize(jsonNode.get("size").asInt());
                List<Entity> entities = new ArrayList<>();
                ArrayNode arrayNode = JsonUtils.readArray(jsonNode.get("entities").toString());
                for (JsonNode node : arrayNode) {
                    Entity entity = new Entity();
                    entity.setEntityName(node.get("entity_name").asText());
                    entity.setCreateTime(DateUtils.parse(node.get("create_time").asText()));
                    entity.setModifyTime(DateUtils.parse(node.get("modify_time").asText()));
                    entities.add(entity);
                }
                response.setEntities(entities);

            } catch (IOException e) {
                log.error("parseListEntityResponse JsonUtils readNode error.result:{}", result);
            }
        }
    }

}
